package com.molichuxing.services.business.service.impl;

import com.molichuxing.framework.dto.Paged;
import com.molichuxing.framework.dto.TabDto;
import com.molichuxing.framework.exception.BizException;
import com.molichuxing.framework.utils.DateUtil;
import com.molichuxing.framework.utils.ObjectCastUtil;
import com.molichuxing.services.business.convertor.Convert;
import com.molichuxing.services.business.dto.request.create.OrderSubscribeCreateBizDto;
import com.molichuxing.services.business.dto.request.modify.OrderExpireModifyBizDto;
import com.molichuxing.services.business.dto.request.modify.OrderModifyBizDto;
import com.molichuxing.services.business.dto.request.modify.OrderPayModifyBizDto;
import com.molichuxing.services.business.dto.response.*;
import com.molichuxing.services.business.service.OrderPurchaseBizService;
import com.molichuxing.services.business.service.OrderSubscribeBizService;
import com.molichuxing.services.exception.OrderExceptionCodeEnum;
import com.molichuxing.services.infrastructure.dto.request.create.OrderCreateDto;
import com.molichuxing.services.infrastructure.dto.request.modify.OrderPayModifyDto;
import com.molichuxing.services.infrastructure.dto.response.OrderDeliveryDto;
import com.molichuxing.services.infrastructure.dto.response.OrderReturnDto;
import com.molichuxing.services.infrastructure.dto.response.OrderSubscribeDto;
import com.molichuxing.services.infrastructure.dto.response.OrderSubscribeSettlementDto;
import com.molichuxing.services.infrastructure.service.*;
import com.molichuxing.services.property.OrderListTypeEnum;
import com.molichuxing.services.property.OrderSubscribeStatusEnum;
import com.molichuxing.services.property.OrderTypeEnum;
import com.molichuxing.services.utils.OrderUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 订阅里程订单组合服务
 *
 * @author zoumingyu
 * @date 2019年8月13日
 */
@Service("orderSubscribeBizService")
public class OrderSubscribeBizServiceImpl implements OrderSubscribeBizService {
    private static final Logger logger = LoggerFactory.getLogger(OrderSubscribeBizServiceImpl.class);

    @Resource
    private OrderSubscribeService orderSubscribeService;

    @Resource
    private OrderDeliveryService orderDeliveryService;

    @Resource
    private OrderReturnService orderReturnService;

    @Resource
    private OrderSubscribeSettlementService orderSubscribeSettlementService;

    @Resource
    private OrderPurchaseBizService orderPurchaseBizService;

    @Resource
    private OrderService orderService;

    @Resource
    private OrderStatusFlowService orderStatusFlowService;

    /**
     * 分页获取订阅里程订单信息
     *
     * @param params   listType：列表类型-enum <br />
     *                 orderStatus：订单状态-enum <br />
     *                 orderCode：订单号-long <br />
     *                 userIds：用户id-list <br />
     *                 storeIds：门店id-list <br />
     *                 orderTimeStart：下单开始时间-LocalDate <br />
     *                 orderTimeEnd：下单结束时间-LocalDate <br />
     *                 isHaveSuborder：有无续订-boolean
     * @param pageNum  页数
     * @param pageSize 每页条数
     * @return
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    @Override
    public Paged<OrderSubscribeBizDto> getOrderList(Map<String, Object> params, int pageNum, int pageSize)
            throws Exception {
        Paged<OrderSubscribeBizDto> result = null;
        // 统计每种状态下的数据量
        List<TabDto> tabs = null;
        Integer source = ObjectCastUtil.castInteger(params.get("source"));
        if (source != null && source == 2) {
            tabs = orderSubscribeService.getStatusStatistics(
                    ObjectCastUtil.castEmun(params.get("listType"), OrderListTypeEnum.class),
                    ObjectCastUtil.castList(params.get("dealerStoreIds")));
        } else {
            tabs = orderSubscribeService
                    .getStatusStatistics(ObjectCastUtil.castEmun(params.get("listType"), OrderListTypeEnum.class));
        }

        result = new Paged<>(new ArrayList<>(), tabs, 0, pageSize);

        Paged<OrderSubscribeDto> orderSubscribeDtoPage = orderSubscribeService.getOrderList(params, pageNum, pageSize);
        if (orderSubscribeDtoPage == null) {
            return result;
        } else if (orderSubscribeDtoPage.isEmpty()) {
            return result.setTotal(orderSubscribeDtoPage.getTotal());
        }

        for (OrderSubscribeDto orderSubscribeDto : orderSubscribeDtoPage.getList()) {
            result.getList().add(this.convert(orderSubscribeDto));
        }
        result.setTotal(orderSubscribeDtoPage.getTotal());
        return result;
    }

    /**
     * 订阅里程订单信息
     *
     * @param orderCode 订单号
     * @return
     */
    @Override
    public OrderSubscribeBizDto getOrderSubscribe(Long orderCode) {
        OrderSubscribeBizDto result = null;
        OrderSubscribeDto orderSubscribeDto = orderSubscribeService.getOrderSubscribe(orderCode);
        if (orderSubscribeDto == null) {
            return result;
        }
        return this.convert(orderSubscribeDto);
    }

    /**
     * 订阅里程dto转换并查询加购信息
     *
     * @param orderSubscribeDto
     * @return
     */
    private OrderSubscribeBizDto convert(OrderSubscribeDto orderSubscribeDto) {
        OrderSubscribeBizDto result = Convert.toOrderSubscribeBizDto(orderSubscribeDto);
        OrderPurchaseBizDto orderPurchaseBizDto = orderPurchaseBizService.getOrderPurchase(result.getOrderCode());
        if (orderPurchaseBizDto == null) {
            return result;
        }
        result.setPurchaseMileage(orderPurchaseBizDto.getTotalPurchaseMileage());
        result.setPurchaseFee(orderPurchaseBizDto.getTotalPurchaseFee());
        result.setBeyondMileage(orderPurchaseBizDto.getTotalBeyondMileage());
        result.setBeyondFee(orderPurchaseBizDto.getTotalBeyondFee());

        return result;
    }

    /**
     * 订阅里程订单详情信息（包涵交车、还车、加购、结算等相关信息）
     *
     * @param orderCode 订单号
     * @return
     */
    @Override
    public OrderSubscribeDetailsBizDto getOrderSubscribeDetails(Long orderCode) {
        OrderSubscribeDetailsBizDto result = null;
        // 查询订阅里程订单
        OrderSubscribeDto orderSubscribeDto = orderSubscribeService.getOrderSubscribe(orderCode);
        if (orderSubscribeDto == null) {
            return result;
        }
        result = Convert.toOrderSubscribeDetailsBizDto(orderSubscribeDto);
        if (orderSubscribeDto.getParentOrderCode() == null) {
            // 主订单，才有交车信息
            // 查询交车信息
            OrderDeliveryDto orderDeliveryDto = orderDeliveryService.getOrderDelivery(orderCode);
            if (orderDeliveryDto == null) {
                // 未交车
                return result;
            }
            result.setDeliveryd(Convert.toOrderDeliveryBizDto(orderDeliveryDto));
        }

        // 查询加购信息
        OrderPurchaseBizDto orderPurchaseBizDto = orderPurchaseBizService.getOrderPurchase(result.getOrderCode());
        if (orderPurchaseBizDto != null) {
            result.setPurchaseMileage(orderPurchaseBizDto.getTotalPurchaseMileage());
            result.setPurchaseFee(orderPurchaseBizDto.getTotalPurchaseFee());
            result.setBeyondMileage(orderPurchaseBizDto.getTotalBeyondMileage());
            result.setBeyondFee(orderPurchaseBizDto.getTotalBeyondFee());
            result.setPurchase(orderPurchaseBizDto);
        }

        // 查询还车信息
        OrderReturnDto orderReturnDto = orderReturnService.getOrderReturn(orderCode);
        if (orderReturnDto == null) {
            // 未还车
            return result;
        }
        result.setReturnd(Convert.toOrderReturnBizDto(orderReturnDto));

        // 查询结算信息
        OrderSubscribeSettlementDto orderSubscribeSettlementDto = orderSubscribeSettlementService
                .getOrderSubscribeSettlement(orderCode);
        if (orderSubscribeSettlementDto == null) {
            return result;
        }
        result.setSettlement(Convert.toOrderSubscribeSettlementBizDto(orderSubscribeSettlementDto));

        return result;
    }

    /**
     * 根据用户id查询订阅里程订单信息
     *
     * @param userId 用户id
     * @return
     */
    @Override
    public List<UserOrderBizDto> getOrderSubscribeByUser(Integer userId) {
        return userId == null ? null
                : Convert.toUserOrderBizDtoBySubscribe(orderSubscribeService.getOrderListByUser(userId));
    }

    /**
     * 根据车辆id查询订阅里程订单信息
     *
     * @param carId 车辆id
     * @return
     */
    @Override
    public List<CarOrderBizDto> getOrderSubscribeByCar(Integer carId) {
        return carId == null ? null
                : Convert.toCarOrderBizDtoBySubscribe(orderSubscribeService.getOrderListByCar(carId));
    }

    /**
     * 根据车辆id查询订阅里程订单信息
     *
     * @param carId    车辆id
     * @param storeIds 门店ids
     * @return
     */
    @Override
    public List<CarOrderBizDto> getOrderSubscribeByCar(Integer carId, List<Integer> storeIds) {
        return carId == null ? null
                : Convert.toCarOrderBizDtoBySubscribe(orderSubscribeService.getOrderListByCar(carId, storeIds));
    }

    /**
     * 获取用车实况信息
     *
     * @param orderCode 订单号
     * @return
     */
    @Override
    public OrderUsedCarBizDto getOrderUsedCar(Long orderCode) {
        OrderUsedCarBizDto result = null;

        OrderSubscribeBizDto orderSubscribeBizDto = getOrderSubscribeDetails(orderCode);
        if (orderSubscribeBizDto == null) {
            return result;
        }
        result = Convert.toOrderUsedCarBizDto(orderSubscribeBizDto);

        return result;
    }

    /**
     * 根据用户查询用车中的车辆id
     *
     * @param userId 用户id
     * @return
     */
    @Override
    public List<OrderCarInfoAppDto> getOrderSubscribeCarIdByUser(Integer userId, Integer orderStatus) {
        return orderSubscribeService.getUseCarIdByUser(userId, orderStatus);
    }

    /**
     * 新增订阅里程订单
     *
     * @param createDto
     * @return 订单号
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public Long createOrderSubscribe(OrderSubscribeCreateBizDto createDto) {
        // 订单号
        Long orderCode = OrderUtil.getOrderCode();
        // 新增订单表信息
        orderService.create(new OrderCreateDto(orderCode, OrderTypeEnum.SUBSCRIBE));
        // 新增订阅里程订单
        orderSubscribeService.create(Convert.toOrderSubscribeCreateDto(orderCode, createDto));
        // 新增订单流转信息
        orderStatusFlowService.createOrderStatusFlow(Convert.toOrderStatusFlowCreateDto(orderCode, createDto));

        return orderCode;
    }

    /**
     * 订单修改
     *
     * @param modifyDto
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public Boolean modifySubscribeStatus(OrderModifyBizDto modifyDto) {
        // 修改订单状态
        if (!orderSubscribeService.modify(modifyDto.getOrderCode(),
                (OrderSubscribeStatusEnum) modifyDto.getPreOrderStatus(),
                (OrderSubscribeStatusEnum) modifyDto.getOrderStatus())) {
            return false;
        }
        // 新增订单流转信息
        orderStatusFlowService
                .createOrderStatusFlow(Convert.toOrderStatusFlowCreateDto(modifyDto, OrderTypeEnum.SUBSCRIBE));
        return true;
    }

    private OrderSubscribeDto getModify(Long orderCode, OrderSubscribeStatusEnum orderStatus) {
        return getModify(orderCode, Arrays.asList(orderStatus));
    }

    private OrderSubscribeDto getModify(Long orderCode, List<OrderSubscribeStatusEnum> orderStatusList) {
        // 查询订单信息
        OrderSubscribeDto orderSubscribeDto = orderSubscribeService.getOrderSubscribe(orderCode);
        if (orderSubscribeDto == null) {
            logger.error("[getModify]修改订阅订单信息异常，订单({})不存在", orderCode);
            throw new BizException(OrderExceptionCodeEnum.NOT_EXIST.getCode(), "订单号(" + orderCode + ")对应订单不存在");
        } else if (!orderStatusList.contains(orderSubscribeDto.getOrderStatus())) {
            StringBuffer sb = new StringBuffer();
            for (OrderSubscribeStatusEnum orderSubscribeStatusEnum : orderStatusList) {
                sb.append(orderSubscribeStatusEnum.getName() + " ");
            }
            logger.error("[getModify]修改订阅订单信息异常，订单({}:{})不状态({})不为{}", orderSubscribeDto.getOrderCode(),
                    orderSubscribeDto.getOrderStatus().getValue(), orderSubscribeDto.getOrderStatus().getName(),
                    sb.toString());
            throw new BizException(OrderExceptionCodeEnum.ERROR.getCode(),
                    "修改订单异常，订单(" + orderSubscribeDto.getOrderCode() + ")状态("
                            + orderSubscribeDto.getOrderStatus().getName() + ")不为待支付");
        }

        return orderSubscribeDto;
    }

    /**
     * 支付成功后修改订单信息
     *
     * @param modifyBizDto
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public Boolean modifyPaySuccess(OrderPayModifyBizDto modifyBizDto) {
        // 查询订单信息
        OrderSubscribeDto orderSubscribeDto = getModify(modifyBizDto.getOrderCode(),
                Arrays.asList(OrderSubscribeStatusEnum.TRADE_UNPAID, OrderSubscribeStatusEnum.TRADE_CANCELED));

        // 修改订单信息
        OrderPayModifyDto modifyDto = null;
        OrderSubscribeStatusEnum status = null;
        // 判断订单是否是续订单
        if (orderSubscribeDto.getParentOrderCode() == null) {
            // 主订单
            status = OrderSubscribeStatusEnum.TRADE_UNAUDIT;
            // 计算提车截止日-当天
            LocalDateTime deliveryDeadline = DateUtil.getDayEnd(modifyBizDto.getPayTime());
            modifyDto = Convert.toOrderPayModifyDto(modifyBizDto, status, orderSubscribeDto.getTransportTime(),
                    deliveryDeadline);
        } else {
            // 续订单
            status = OrderSubscribeStatusEnum.TRADE_UNUSE;
            // 修改主订单信息
            if (!orderSubscribeService.modifyRenew(orderSubscribeDto.getParentOrderCode())) {
                logger.error("订单({})续订完成修改失败", orderSubscribeDto.getParentOrderCode());
                return false;
            }
            LocalDateTime deliveryDeadline = DateUtil.getDayEnd(modifyBizDto.getPayTime());
            modifyDto = Convert.toOrderPayModifyDto(modifyBizDto, status, orderSubscribeDto.getTransportTime(),
                    deliveryDeadline);
            modifyDto.setLeaseInception(null);
            modifyDto.setLeaseExpire(null);
        }
        if (!orderSubscribeService.modifyPay(modifyDto)) {
            logger.error("支付完修改订阅订单({})失败", modifyDto.getOrderCode());
            throw new BizException("支付完修改订阅订单失败");
        }
        // 新增流转信息
        orderStatusFlowService.createOrderStatusFlow(Convert.toOrderStatusFlowCreateDto(modifyBizDto, status));
        return true;
    }

    /**
     * 获取有效订阅续订订单信息（已支付）
     *
     * @param parentOrderCode 父订单号
     * @return
     */
    @Override
    public OrderSubscribeBizDto getEffectiveOrderSubscribeByParent(Long parentOrderCode) {
        OrderSubscribeBizDto result = null;
        OrderSubscribeDto orderSubscribeDto = orderSubscribeService.getEffectiveOrderSubscribeByParent(parentOrderCode);
        if (orderSubscribeDto == null) {
            return result;
        }
        return this.convert(orderSubscribeDto);
    }

    /**
     * 订单到期修改
     *
     * @param modifyBizDtos
     * @return 返回失败订单号, null则代表全部成功
     */
    @Override
    public List<Long> modifyOrderExpire(List<OrderExpireModifyBizDto> modifyBizDtos) {
        List<Long> result = new ArrayList<>();
        if (modifyBizDtos == null || modifyBizDtos.isEmpty()) {
            return null;
        }
        StringBuffer errorMsg = new StringBuffer();
        try {
            modifyBizDtos.forEach(modifyBizDto -> {
                // 根据订单号，查询订单信息
                OrderSubscribeDto orderSubscribeDto = orderSubscribeService
                        .getOrderSubscribe(modifyBizDto.getOrderCode());
                if (orderSubscribeDto == null) {
                    errorMsg.append("订单(" + modifyBizDto.getOrderCode() + ")不存在\r\n");
                    result.add(modifyBizDto.getOrderCode());
                    return;
                }
                // 判断是否存在续订
                if (orderSubscribeDto.getIsHaveSuborder()) {
                    // 存在续订，修改主订单为已完成，并修改续订单为用车中
                    try {
                        if (!modifyOrderExpireSettle(modifyBizDto)) {
                            errorMsg.append("订单(" + modifyBizDto.getOrderCode() + ")修改已完成失败\r\n");
                            result.add(modifyBizDto.getOrderCode());
                        }
                    } catch (Exception e) {
                        errorMsg.append("订单(" + modifyBizDto.getOrderCode() + ")修改已完成失败(" + e.getMessage() + ")\r\n");
                        result.add(modifyBizDto.getOrderCode());
                    }
                } else {
                    // 不存在，修改主订单信息，记录订单结束里程
                    try {
                        if (!modifyOrderExpireEnd(modifyBizDto)) {
                            errorMsg.append("订单(" + modifyBizDto.getOrderCode() + ")修改记录里程失败\r\n");
                            result.add(modifyBizDto.getOrderCode());
                        }
                    } catch (Exception e) {
                        errorMsg.append("订单(" + modifyBizDto.getOrderCode() + ")修改记录里程失败(" + e.getMessage() + ")\r\n");
                        result.add(modifyBizDto.getOrderCode());
                    }
                }
            });
        } finally {
            if (errorMsg.length() > 0) {
                logger.error("[modifyOrderExpire]" + errorMsg.toString());
            }
        }
        return result.isEmpty() ? null : result;
    }

    /**
     * 修改主订单信息，记录订单结束里程
     *
     * @param modifyBizDto
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public boolean modifyOrderExpireEnd(OrderExpireModifyBizDto modifyBizDto) {
        return orderSubscribeService.modifyEndMileageByExpire(modifyBizDto.getOrderCode(),
                modifyBizDto.getCurrentMileage());
    }

    /**
     * 修改主订单为已完成，并修改续订单为用车中
     *
     * @param modifyBizDto
     * @return
     */
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public boolean modifyOrderExpireSettle(OrderExpireModifyBizDto modifyBizDto) throws BizException, Exception {
        if (!orderSubscribeService.modifyFinish(Convert.toOrderFinishModifyDto(modifyBizDto),
                OrderSubscribeStatusEnum.TRADE_USE)) {
            // 修改失败
            return false;
        }
        // 新增流转信息
        orderStatusFlowService.createOrderStatusFlow(
                Convert.toOrderStatusFlowCreateDto(modifyBizDto, OrderSubscribeStatusEnum.RETURN_FINISH));
        // 查询待用车续订单
        OrderSubscribeDto renew = orderSubscribeService.getOrderSubscribeByParent(modifyBizDto.getOrderCode(),
                OrderSubscribeStatusEnum.TRADE_UNUSE);
        if (renew == null) {
            logger.error("[modifyOrderExpireSettle]订单(" + modifyBizDto.getOrderCode() + ")不存在待用车续订单");
            throw new BizException("订单(" + modifyBizDto.getOrderCode() + ")不存在待用车续订单");
        }
        // 计算预警里程(当前里程+购买里程)
        Integer warningMileage = modifyBizDto.getCurrentMileage() + renew.getBaseMileage() + renew.getPackageMileage()
                + renew.getGiftMileage();
        // 修改续订单为用车中
        if (!orderSubscribeService.modifyUse(Convert.toOrderUseModifyDto(modifyBizDto, renew, warningMileage))) {
            logger.error("[modifyOrderExpireSettle]续订单(" + renew.getOrderCode() + ")修改用车中失败");
            throw new BizException("续订单(" + renew.getOrderCode() + ")修改用车中失败");
        }
        // 新增流转信息
        orderStatusFlowService
                .createOrderStatusFlow(Convert.toOrderStatusFlowCreateDto(renew, OrderSubscribeStatusEnum.TRADE_USE));

        return true;
    }

    /**
     * 订单结算修改
     *
     * @param modifyBizDto
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public Boolean modifySettlement(OrderPayModifyBizDto modifyBizDto) {
        // 修改订单状态
        if (!orderSubscribeService.modify(modifyBizDto.getOrderCode(),
                OrderSubscribeStatusEnum.RETURN_UNPAID, OrderSubscribeStatusEnum.RETURN_FINISH)) {
            logger.error("[modifySettlement]订单({})结算修改状态失败", modifyBizDto.getOrderCode());
            return false;
        }
        // 新增订单流转信息
        orderStatusFlowService
                .createOrderStatusFlow(
                        Convert.toOrderStatusFlowCreateDto(modifyBizDto, OrderSubscribeStatusEnum.RETURN_FINISH));

        // 修改结算表信息
        if (!orderSubscribeSettlementService.modifyPay(Convert.toOrderPayModifyDto(modifyBizDto))) {
            logger.error("[modifySettlement]订单({})结算修改结算信息失败", modifyBizDto.getOrderCode());
            throw new BizException("订单(" + modifyBizDto.getOrderCode() + ")结算修改结算信息失败");
        }
        return true;
    }
}
